package irc

import (
	"context"
	"fmt"
	"ircove.com/common"
	"log"
	"net"
	"sync"
	"sync/atomic"
	"time"
)

type ServerOptions struct {
	Network     string
	Address     string
	MaxConnSize uint64
	TimeOut     int64
}

type Server struct {
	Opts       *ServerOptions
	Clients    map[string]*Client
	wg         *sync.WaitGroup
	mu         sync.Mutex
	ConnSize   uint64
	clientids  uint64
	ServerName string
}

func (srv *Server) Start() {
	ip_addr, err := net.ResolveTCPAddr(srv.Opts.Network, srv.Opts.Address)
	if err != nil {
		log.Fatalln(err)
		return
	}
	ln, err := net.ListenTCP(srv.Opts.Network, ip_addr)
	if err != nil {
		log.Fatalln(err)
		return
	}
	defer ln.Close()
	for {

		conn, err := ln.AcceptTCP()
		if err != nil {
			log.Fatalln(err)
			continue
		}
		//最大连接限制
		curconnsize := atomic.AddUint64(&srv.ConnSize, 1)
		if curconnsize > srv.Opts.MaxConnSize {
			conn.Close()
			continue
		}
		conn.SetNoDelay(true)
		client := NewsClient(srv, conn)
		go HandleConnection(srv, client)
	}
}
func (s *Server) Stop() {

}

func HandleConnection(srv *Server, client *Client) {
	defer func() {
		if p := recover(); p != nil {
			fmt.Println("panic recover! p:", p)
		}
		return
	}()

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	go readloop(ctx, client)
	lasttime := time.Now().Unix()

	for {
		select {
		case <-time.After(client.ReadTimeout):
			if time.Now().Unix()-lasttime >= srv.Opts.TimeOut {
				goto ForEnd
			}
		case request := <-client.Reqchain:
			go Handler(ctx, client, request)
		case response, ok := <-client.Rspchain:
			if !ok {
				return
			}
			err := writemessage(client, response)
			if common.IsNewWorkError(err) {
				goto ForEnd
			}
			if err!=nil {
				log.Println(err)
			}
			lasttime = time.Now().Unix()
		case _, ok := <-client.Closechain:
			if !ok {
				return
			}
			goto ForEnd
		}
	}
ForEnd:
	{
		client.conn.Close()
	}
}

func writemessage(client *Client, response *Message) error {
	if err := client.conn.SetReadDeadline(time.Now().Add(client.ReadTimeout)); err != nil {
		//log.Printf("writemessage  SetReadDeadline err :%s", err.Error())
		return common.NetWorkError.Clone(fmt.Sprintf("writemessage  SetReadDeadline err :%s", err.Error()))
	}
	err := response.Encode(client.conn)
	if err != nil {
		return err
	}
	return nil
}

func readloop(ctx context.Context, client *Client) {

	for {
		select {
		case <-ctx.Done():
			return
		default:
			if err := client.conn.SetReadDeadline(time.Now().Add(client.ReadTimeout)); err != nil {
				log.Printf("readloop setreadde SetReadDeadline err :%s\n", err.Error())
				client.Closechain <- 1
				return
			}
			message := new(Message)
			err := message.Decode(client.conn)
			if err != nil {
				if common.IsNewWorkError(err) {
					client.Closechain <- 1
					return
				}
				log.Printf("readloop  message Decode err :%s\n", err.Error())
			}
			client.Reqchain <- message
		}
	}
}

func Handler(ctx context.Context, client *Client, request *Message) {
	rspfunc := SelectHander(request)
	if rspfunc != nil {
		rsp := rspfunc(ctx, client, request)
		if rsp != nil {
			client.Rspchain <- rsp
		}
	} else {
		log.Printf("rspfunc no fond %d", request.Header.MessageID)
	}
}
